Skip to content

Fix sync client dropping lines#960

Merged
simolus3 merged 2 commits into
mainfrom
fix-injectable-event-loss
May 13, 2026
Merged

Fix sync client dropping lines#960
simolus3 merged 2 commits into
mainfrom
fix-injectable-event-loss

Conversation

@simolus3
Copy link
Copy Markdown
Contributor

A race condition in injectable (used by the Rust sync client to forward sync lines along with local events like a completed upload) could cause sync lines to be ignored. In particular, a local write + sync caused events where the data line in a checkpoint_diff, data, checkpoint_complete got dropped, causing checksum verification errors.

The issue is caused by this sequence of events:

  1. We await an event in an injectable stream, causing it to fetch a sync line from the source upstream (waiter is set, pendingSourceEvent is null).
  2. We call inject, making the initial event complete (waiter is now null).
  3. Before the initial upstream event completes, we call next() again. pendingSourceEvent is still null because the initial source event has not completed, so we try to call source.next() again. Async iterators aren't meant to be used concurrently like this, and resolveWaiter may loose events since there is only one slot for a pending source event once the two complete.

The fix is to not call source.next() again, I've manually verified this in Steven's convex demo where this reproduces consistently.

Product visibility

This doesn't change anything that needs to be documented, but I'm adding the label due to the severity of the issue and in case we get addititional reports for this.

AI usage disclaimer

The issue was found by Claude after manual testing; it also generated the fix and test. I've manually verified the fix in the convex demo.

Closes #954.

@simolus3 simolus3 requested a review from stevensJourney May 13, 2026 16:26
@simolus3 simolus3 added the Product Visibility This requires documentation changes and or announcing. label May 13, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 13, 2026

🦋 Changeset detected

Latest commit: 4925506

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
@powersync/common Patch
@powersync/adapter-sql-js Patch
@powersync/node Patch
@powersync/op-sqlite Patch
@powersync/react-native Patch
@powersync/tanstack-react-query Patch
@powersync/web Patch
@powersync/diagnostics-app Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@rkistner
Copy link
Copy Markdown
Contributor

@simolus3 Do you know when the issue has been introduced?

Just wondering if it has always been present if the Rust sync client was used, or if it was a regression introduced at some point.

@simolus3
Copy link
Copy Markdown
Contributor Author

#821 originally introduced the bug and this has likely been an issue since then. It's possible that the control flow changes in #951 made the race condition more likely.

@simolus3
Copy link
Copy Markdown
Contributor Author

The isolated demos check fails because of pnpm11. There's an open PR for that, I'll merge this with failing checks because we likely want to release this first.

@simolus3 simolus3 merged commit 8704578 into main May 13, 2026
14 of 16 checks passed
@simolus3 simolus3 deleted the fix-injectable-event-loss branch May 13, 2026 19:18
Stvad added a commit to Stvad/knowledge-medium that referenced this pull request May 14, 2026
Backports powersync-ja/powersync-js#960. Without it, ~1 in 3 local
writes triggers a checksum mismatch and a full bucket wipe (see #954).

patch-package applies the diff on every install so CI ships it too;
remove once a release with the upstream fix is published.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product Visibility This requires documentation changes and or announcing.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bucket checksum mismatch on every few user edits → deleteBucket → full re-sync

3 participants